<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>10.Ivy编译器的视图数据和依赖解析 | 被删的前端游乐场</title>
    <meta name="generator" content="VuePress 1.8.2">
    
    <meta name="description" content="Just playing around">
    
    <link rel="preload" href="/front-end-playground/assets/css/0.styles.6ad2a9ca.css" as="style"><link rel="preload" href="/front-end-playground/assets/js/app.1e2670bf.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/2.38d016d1.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/3.e3f029cb.js" as="script"><link rel="preload" href="/front-end-playground/assets/js/109.a96adbae.js" as="script">
    <link rel="stylesheet" href="/front-end-playground/assets/css/0.styles.6ad2a9ca.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/front-end-playground/" class="home-link router-link-active"><!----> <span class="site-name">被删的前端游乐场</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link">前端领域</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link router-link-active">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/front-end-work/" class="nav-link">前端与工作</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/front-end-playground/" class="nav-link">概述</a></div><div class="nav-item"><a href="/front-end-playground/front-end-basic/" class="nav-link">前端领域</a></div><div class="nav-item"><a href="/front-end-playground/vue/" class="nav-link">Vue学习</a></div><div class="nav-item"><a href="/front-end-playground/wxapp/" class="nav-link">小程序学习</a></div><div class="nav-item"><a href="/front-end-playground/front-end-others/" class="nav-link router-link-active">百家齐放</a></div><div class="nav-item"><a href="/front-end-playground/front-end-addon/" class="nav-link">前端的进击</a></div><div class="nav-item"><a href="/front-end-playground/front-end-work/" class="nav-link">前端与工作</a></div><div class="nav-item"><a href="/front-end-playground/faq.html" class="nav-link">FAQ</a></div> <a href="https://github.com/godbasin/front-end-playground" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0" style="padding-top:10px;"><div class="kitty-main" data-v-2b653b36><span class="stand" data-v-2b653b36></span> <div class="cat" data-v-2b653b36><div class="body" data-v-2b653b36></div> <div class="head" data-v-2b653b36><div class="ear" data-v-2b653b36></div> <div class="ear" data-v-2b653b36></div></div> <div class="face" data-v-2b653b36><div class="nose" data-v-2b653b36></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div></div> <div class="tail-container" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36></div></div></div></div></div></div></div></div></div></div> <p class="sidebar-heading open"><span>Angular框架解读</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-0-prestart.html" class="sidebar-link">0.预热篇</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-metadata.html" class="sidebar-link">1.元数据和装饰器</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-dom-define.html" class="sidebar-link">2.视图抽象定义</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-zonejs.html" class="sidebar-link">3.Zone区域之zone.js</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-zone-ngzone.html" class="sidebar-link">4.Zone区域之ngZone</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-module.html" class="sidebar-link">5.模块化组织</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-1-basic-concepts.html" class="sidebar-link">6.依赖注入的基本概念</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-2-hierarchical-di.html" class="sidebar-link">7.多级依赖注入设计</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-3-bootstrap.html" class="sidebar-link">8.依赖注入的引导过程</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-ivy-0-design.html" class="sidebar-link">9.Ivy编译器整体设计</a></li><li><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-ivy-1-view-data-and-node-injector.html" aria-current="page" class="active sidebar-link">10.Ivy编译器的视图数据和依赖解析</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-ivy-1-view-data-and-node-injector.html#ivy-模型" class="sidebar-link">Ivy 模型</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-ivy-1-view-data-and-node-injector.html#ivy-中-的-di" class="sidebar-link">Ivy 中 的 DI</a></li><li class="sidebar-sub-header"><a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-ivy-1-view-data-and-node-injector.html#总结" class="sidebar-link">总结</a></li></ul></li></ul></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>玩转 Angular</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>试试 Cycle.js</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>D3.js 和 Tree</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>试试 Three.js</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>BOX2D.js 文档与教程</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><p>作为“为大型前端项目”而设计的前端框架，Angular 其实有许多值得参考和学习的设计，本系列主要用于研究这些设计和功能的实现原理。本文主要介绍在 Angular 的 Ivy 编译器中，是如何管理和查找视图数据的。</p> <h2 id="ivy-模型"><a href="#ivy-模型" class="header-anchor">#</a> Ivy 模型</h2> <p>在<a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-ivy-0-design.html">上一节《Ivy 编译器整体设计》</a>中，我们从整体上介绍了 Ivy 编译器主要做的一些事情，包括模板编译、TypeScript 解析器等。我们可以看到 Ivy 编译器实现了更优的 Tree-shaking 支持、组件的延迟加载、支持增量编译等，而达到这些效果的一个核心设计点便在于视图的解析和数据管理。</p> <h3 id="视图数据-lview-tview"><a href="#视图数据-lview-tview" class="header-anchor">#</a> 视图数据 LView/TView</h3> <p>在 Angular Ivy 中，使用了<code>LView</code>和<code>TView.data</code>来管理和跟踪渲染模板所需要的内部数据。</p> <p>其中，<code>LView</code>存储了从模板调用指令时，处理指令所需的所有信息。每个嵌入式视图和组件视图都有自己的<code>LView</code>，我们来看看<code>LView</code>的定义：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">LView</span> <span class="token keyword">extends</span> <span class="token class-name"><span class="token builtin">Array</span><span class="token operator">&lt;</span><span class="token builtin">any</span><span class="token operator">&gt;</span></span> <span class="token punctuation">{</span>
  <span class="token comment">// 插入该 LView 的节点</span>
  <span class="token punctuation">[</span><span class="token constant">HOST</span><span class="token punctuation">]</span><span class="token operator">:</span> RElement <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 此视图的静态数据</span>
  <span class="token keyword">readonly</span> <span class="token punctuation">[</span><span class="token constant">TVIEW</span><span class="token punctuation">]</span><span class="token operator">:</span> TView<span class="token punctuation">;</span>

  <span class="token comment">// 父视图</span>
  <span class="token punctuation">[</span><span class="token constant">PARENT</span><span class="token punctuation">]</span><span class="token operator">:</span> LView <span class="token operator">|</span> LContainer <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 下一个同级视图或容器</span>
  <span class="token punctuation">[</span><span class="token constant">NEXT</span><span class="token punctuation">]</span><span class="token operator">:</span> LView <span class="token operator">|</span> LContainer <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 对此视图有效的查询-视图中的节点将报告给这些查询</span>
  <span class="token punctuation">[</span><span class="token constant">QUERIES</span><span class="token punctuation">]</span><span class="token operator">:</span> LQueries <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 存储当前 LView 插入位置的 TNode</span>
  <span class="token punctuation">[</span><span class="token constant">T_HOST</span><span class="token punctuation">]</span><span class="token operator">:</span> TNode <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 当视图被破坏时，需要释放侦听器，并且必须取消订阅输出</span>
  <span class="token punctuation">[</span><span class="token constant">CLEANUP</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 上下文信息</span>
  <span class="token punctuation">[</span><span class="token constant">CONTEXT</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token operator">|</span> RootContext <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 在咨询了元素注入器之后，将使用可选的模块注入器作为回退</span>
  <span class="token keyword">readonly</span> <span class="token punctuation">[</span><span class="token constant">INJECTOR</span><span class="token punctuation">]</span><span class="token operator">:</span> Injector <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 用于创建渲染器的工厂</span>
  <span class="token punctuation">[</span><span class="token constant">RENDERER_FACTORY</span><span class="token punctuation">]</span><span class="token operator">:</span> RendererFactory3<span class="token punctuation">;</span>

  <span class="token comment">// 要用于此视图的渲染器</span>
  <span class="token punctuation">[</span><span class="token constant">RENDERER</span><span class="token punctuation">]</span><span class="token operator">:</span> Renderer3<span class="token punctuation">;</span>

  <span class="token comment">// 引用层次结构中此 LView 下的第一个 LView 或 LContainer</span>
  <span class="token punctuation">[</span><span class="token constant">CHILD_HEAD</span><span class="token punctuation">]</span><span class="token operator">:</span> LView <span class="token operator">|</span> LContainer <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 层次结构中此 LView 下的最后一个 LView 或 LContainer</span>
  <span class="token punctuation">[</span><span class="token constant">CHILD_TAIL</span><span class="token punctuation">]</span><span class="token operator">:</span> LView <span class="token operator">|</span> LContainer <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 查看声明此视图的模板的位置</span>
  <span class="token punctuation">[</span><span class="token constant">DECLARATION_VIEW</span><span class="token punctuation">]</span><span class="token operator">:</span> LView <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

  <span class="token comment">// 指向声明组件视图，用于跟踪已移植的 LView</span>
  <span class="token punctuation">[</span><span class="token constant">DECLARATION_COMPONENT_VIEW</span><span class="token punctuation">]</span><span class="token operator">:</span> LView<span class="token punctuation">;</span>

  <span class="token comment">// 嵌入视图的声明点（基于 &lt;ng-template&gt; 的内容实例化的声明点），其他类型的视图为 null</span>
  <span class="token punctuation">[</span><span class="token constant">DECLARATION_LCONTAINER</span><span class="token punctuation">]</span><span class="token operator">:</span> LContainer <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>我们能看到，<code>LView</code>中存储了足够多的信息，这样的设计使单个数组可以以紧凑的形式包含模板渲染所需的所有必要数据。</p> <p>其中，<code>[TVIEW]</code>为该视图的静态数据，存储了所有可在模板实例之间共享的信息（比如<code>template</code>、<code>components</code>、<code>data</code>以及各种钩子），以便可以轻松地在 DI 中遍历节点树并获取与节点（存储指令<code>defs</code>的节点）关联的<code>TView.data</code>数组。这些信息存储在<code>ComponentDef.tView</code>中。</p> <p>显然，<code>LView</code>还存储了除此之外的所有渲染模板需要的信息，比如：</p> <ul><li><code>[PARENT]</code>用于存储父视图。在处理特定视图时，Ivy 将<code>viewData</code>设置为该<code>LView</code>；完成该视图的处理后，将<code>viewData</code>设置回原始<code>viewData</code>之前的状态（父<code>LView</code>）</li> <li><code>[NEXT]</code>用来链接组件视图和跨容器的视图</li> <li><code>[T_HOST]</code>存储当前<code>LView</code>插入位置的<code>TNode</code>，因为“子级”除了插入到“父级”中，还可以插入到任何地方，因此不能将插入信息存储在<code>TView</code>中</li> <li><code>[DECLARATION_VIEW]</code>用于存储“声明视图”（声明模板的视图），因为动态创建的视图的模板可以在与插入的视图不同的视图中声明，因此，上下文应继承自声明视图树，而不是插入视图树</li> <li><code>[CHILD_HEAD]</code>存储引用层次结构中此<code>LView</code>下的第一个<code>LView</code>或<code>LContainer</code>，以便视图可以遍历其嵌套视图以除去侦听器并调用<code>onDestroy</code>回调</li> <li><code>[CHILD_TAIL]</code>存储层次结构中此<code>LView</code>下的最后一个<code>LView</code>或<code>LContainer</code>，尾部使 Ivy 可以快速向视图列表的末尾添加新状态，而不必从第一个孩子开始传播</li></ul> <p><code>LView</code>的设计，可以为每个视图保留单独的状态以方便视图的插入/删除，因此我们不必根据存在的视图来编辑数据数组。</p> <h3 id="lview-tview-data-数据视图"><a href="#lview-tview-data-数据视图" class="header-anchor">#</a> LView/TView.data 数据视图</h3> <p>在 Ivy 中，<code>LView</code>和<code>TView.data</code>都是数组，它们的索引指向相同的项目。它们的数据视图布局如下：</p> <table><thead><tr><th>Section</th> <th><code>LView</code></th> <th><code>TView.data</code></th></tr></thead> <tbody><tr><td><code>HEADER</code></td> <td>上下文数据</td> <td>大多数为<code>null</code></td></tr> <tr><td><code>DECLS</code></td> <td>DOM、pipe 和本地引用实例</td> <td></td></tr> <tr><td><code>VARS</code></td> <td>绑定值</td> <td>属性名称</td></tr> <tr><td><code>EXPANDO</code></td> <td>host bindings; directive instances; providers; dynamic nodes</td> <td>host prop names; directive tokens; provider tokens; <code>null</code></td></tr></tbody></table> <p>其中：</p> <ul><li><code>HEADER</code>是一个固定的数组大小，其中包含有关模板的上下文信息。主要是诸如父级<code>LView``Sanitizer</code>、<code>TView</code>之类的信息，以及模板渲染所需的更多信息</li> <li><code>DECKS</code>包含 DOM 元素、管道实例和本地引用，<code>DECKS</code>节的大小在组件定义的属性<code>decl</code>中声明</li> <li><code>VARS</code>包含有关如何处理绑定的信息，<code>VARS</code>部分的大小在组件定义的属性<code>var</code>中声明</li> <li><code>EXPANDO</code>包含有关在编译时未知大小的数据的信息。比如<code>Component/Directives</code>，因为 Ivy 在编译时不知道会匹配哪些指令</li></ul> <p>至于具体的例子这里便不展开介绍了，你可以从 <a href="https://github.com/angular/angular/blob/master/packages/core/src/render3/VIEW_DATA.md" target="_blank" rel="noopener noreferrer">DOCS: View Data Explanation<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 文档中找到。</p> <h2 id="ivy-中-的-di"><a href="#ivy-中-的-di" class="header-anchor">#</a> Ivy 中 的 DI</h2> <p>在 Angular DI 中，注入器获取对应的示例依赖于 token 令牌。Ivy 将所有令牌存储在<code>TView.data</code>中，将实例存储在<code>LView</code>中，因此我们可以检索查看该视图的所有注入器。</p> <p>而 DI 查找依赖的过程，离不开<code>NodeInjector</code>。</p> <h3 id="nodeinjector"><a href="#nodeinjector" class="header-anchor">#</a> NodeInjector</h3> <p><a href="">上一节中</a>，我们介绍了 Ivy 编译器中使用增量编译来优化构建速度，增量编译意味着一个库只会根据变更的部分进行重新编译。要做到增量编译，Ivy 编译器不得依赖未直接传递给它的任何输入（可理解为“纯函数”）。使用<code>Lview</code>来存储每个视图的状态和数据，则可以通过 DI 注入依赖的视图数据。</p> <p>在<a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-di-2-hierarchical-di.html">《Angular 框架解读--多级依赖注入设计》</a>一文中，我们介绍了 Angular 中的两种注入器：模块注入器<code>ModuleInjector</code>和元素注入器<code>ElementInjector</code>。Angular 通过依次遍历元素注入器树和模块注入器树来查找提供令牌的注入器。</p> <p>实际上，在 Ivy 中使用<code>NodeInjector</code>替换了 View Engine 中的元素注入器：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">NodeInjector</span> <span class="token keyword">implements</span> <span class="token class-name">Injector</span> <span class="token punctuation">{</span>
  <span class="token function">constructor</span><span class="token punctuation">(</span>
    <span class="token keyword">private</span> _tNode<span class="token operator">:</span>
      <span class="token operator">|</span> TElementNode
      <span class="token operator">|</span> TContainerNode
      <span class="token operator">|</span> TElementContainerNode
      <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">,</span>
    <span class="token keyword">private</span> _lView<span class="token operator">:</span> LView
  <span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>

  <span class="token function">get</span><span class="token punctuation">(</span>token<span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">,</span> notFoundValue<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">any</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">any</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token function">getOrCreateInjectable</span><span class="token punctuation">(</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>_tNode<span class="token punctuation">,</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>_lView<span class="token punctuation">,</span>
      token<span class="token punctuation">,</span>
      <span class="token keyword">undefined</span><span class="token punctuation">,</span>
      notFoundValue
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>其中，<code>getOrCreateInjectable</code>方法从<code>NodeInjectors</code>到<code>ModuleInjector</code>进行遍历，并返回（或创建）与给定令牌关联的值。</p> <h3 id="di-查找依赖的过程"><a href="#di-查找依赖的过程" class="header-anchor">#</a> DI 查找依赖的过程</h3> <p>我们知道 Angular 会构建一棵视图树，该视图树总是以只含一个根元素的伪根视图开始（参考<a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-dom-define.html">《Angular 框架解读--视图抽象定义》</a>）。</p> <p>Ivy 使用<code>LView</code>和<code>TView.data</code>数组来存储视图数据，其中便包括了节点的注入信息。这意味着，<strong><code>NodeInjector</code>需要从<code>LView</code>和<code>TView.data</code>数组中得到具体的视图数据信息</strong>。</p> <p>我们可以从<code>getOrCreateInjectable</code>中看到该过程：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token generic-function"><span class="token function">getOrCreateInjectable</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>
  tNode<span class="token operator">:</span> TDirectiveHostNode <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">,</span>
  lView<span class="token operator">:</span> LView<span class="token punctuation">,</span>
  token<span class="token operator">:</span> Type<span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span> <span class="token operator">|</span> AbstractType<span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span> <span class="token operator">|</span> InjectionToken<span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span><span class="token punctuation">,</span>
  flags<span class="token operator">:</span> InjectFlags <span class="token operator">=</span> InjectFlags<span class="token punctuation">.</span>Default<span class="token punctuation">,</span>
  notFoundValue<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">any</span>
<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token constant">T</span> <span class="token operator">|</span> <span class="token keyword">null</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>tNode <span class="token operator">!==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> bloomHash <span class="token operator">=</span> <span class="token function">bloomHashBitOrFactory</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 如果此处存储的 ID 是一个函数，则这是一个特殊的对象，例如 ElementRef 或 TemplateRef</span>
    <span class="token comment">// 因此只需调用 factory 函数即可创建它</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> bloomHash <span class="token operator">===</span> <span class="token string">&quot;function&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">enterDI</span><span class="token punctuation">(</span>lView<span class="token punctuation">,</span> tNode<span class="token punctuation">,</span> flags<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 无法进入 DI，则尝试使用模块注入器</span>
        <span class="token comment">// 如果使用 @Host 标志注入令牌，则在 Ivy 中不会在模块注入器中搜索该令牌</span>
        <span class="token keyword">return</span> flags <span class="token operator">&amp;</span> InjectFlags<span class="token punctuation">.</span>Host
          <span class="token operator">?</span> <span class="token generic-function"><span class="token function">notFoundValueOrThrow</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>notFoundValue<span class="token punctuation">,</span> token<span class="token punctuation">,</span> flags<span class="token punctuation">)</span>
          <span class="token operator">:</span> <span class="token generic-function"><span class="token function">lookupTokenUsingModuleInjector</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>
              lView<span class="token punctuation">,</span>
              token<span class="token punctuation">,</span>
              flags<span class="token punctuation">,</span>
              notFoundValue
            <span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> value <span class="token operator">=</span> <span class="token function">bloomHash</span><span class="token punctuation">(</span>flags<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>value <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span><span class="token punctuation">(</span>flags <span class="token operator">&amp;</span> InjectFlags<span class="token punctuation">.</span>Optional<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token function">throwProviderNotFoundError</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
          <span class="token keyword">return</span> value<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
        <span class="token function">leaveDI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> bloomHash <span class="token operator">===</span> <span class="token string">&quot;number&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// 对遍历元素注入器树时找到的上一个注入器 TView 的引用</span>
      <span class="token comment">// 这用于了解是否可以在当前注射器上访问 viewProviders</span>
      <span class="token keyword">let</span> previousTView<span class="token operator">:</span> TView <span class="token operator">|</span> <span class="token keyword">null</span> <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
      <span class="token keyword">let</span> injectorIndex <span class="token operator">=</span> <span class="token function">getInjectorIndex</span><span class="token punctuation">(</span>tNode<span class="token punctuation">,</span> lView<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">let</span> parentLocation<span class="token operator">:</span> RelativeInjectorLocation <span class="token operator">=</span> <span class="token constant">NO_PARENT_INJECTOR</span><span class="token punctuation">;</span>
      <span class="token keyword">let</span> hostTElementNode<span class="token operator">:</span> TNode <span class="token operator">|</span> <span class="token keyword">null</span> <span class="token operator">=</span>
        flags <span class="token operator">&amp;</span> InjectFlags<span class="token punctuation">.</span>Host
          <span class="token operator">?</span> lView<span class="token punctuation">[</span><span class="token constant">DECLARATION_COMPONENT_VIEW</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token constant">T_HOST</span><span class="token punctuation">]</span>
          <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

      <span class="token comment">// 如果我们应该跳过此注入器，或者此节点上没有注入器，需先搜索父注入器</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>injectorIndex <span class="token operator">===</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token operator">||</span> flags <span class="token operator">&amp;</span> InjectFlags<span class="token punctuation">.</span>SkipSelf<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        parentLocation <span class="token operator">=</span>
          injectorIndex <span class="token operator">===</span> <span class="token operator">-</span><span class="token number">1</span>
            <span class="token operator">?</span> <span class="token function">getParentInjectorLocation</span><span class="token punctuation">(</span>tNode<span class="token punctuation">,</span> lView<span class="token punctuation">)</span>
            <span class="token operator">:</span> lView<span class="token punctuation">[</span>injectorIndex <span class="token operator">+</span> NodeInjectorOffset<span class="token punctuation">.</span><span class="token constant">PARENT</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>
          parentLocation <span class="token operator">===</span> <span class="token constant">NO_PARENT_INJECTOR</span> <span class="token operator">||</span>
          <span class="token operator">!</span><span class="token function">shouldSearchParent</span><span class="token punctuation">(</span>flags<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
        <span class="token punctuation">)</span> <span class="token punctuation">{</span>
          injectorIndex <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
          previousTView <span class="token operator">=</span> lView<span class="token punctuation">[</span><span class="token constant">TVIEW</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
          injectorIndex <span class="token operator">=</span> <span class="token function">getParentInjectorIndex</span><span class="token punctuation">(</span>parentLocation<span class="token punctuation">)</span><span class="token punctuation">;</span>
          lView <span class="token operator">=</span> <span class="token function">getParentInjectorView</span><span class="token punctuation">(</span>parentLocation<span class="token punctuation">,</span> lView<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>

      <span class="token comment">// 遍历注入器树，直到找到潜​​在的匹配项，或者直到知道*不是*匹配项为止。</span>
      <span class="token keyword">while</span> <span class="token punctuation">(</span>injectorIndex <span class="token operator">!==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        ngDevMode <span class="token operator">&amp;&amp;</span> <span class="token function">assertNodeInjector</span><span class="token punctuation">(</span>lView<span class="token punctuation">,</span> injectorIndex<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// 检查当前的注入器。如果匹配，请查看它是否包含令牌</span>
        <span class="token keyword">const</span> tView <span class="token operator">=</span> lView<span class="token punctuation">[</span><span class="token constant">TVIEW</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        ngDevMode <span class="token operator">&amp;&amp;</span>
          <span class="token function">assertTNodeForLView</span><span class="token punctuation">(</span>
            tView<span class="token punctuation">.</span>data<span class="token punctuation">[</span>injectorIndex <span class="token operator">+</span> NodeInjectorOffset<span class="token punctuation">.</span><span class="token constant">TNODE</span><span class="token punctuation">]</span> <span class="token keyword">as</span> TNode<span class="token punctuation">,</span>
            lView
          <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">bloomHasToken</span><span class="token punctuation">(</span>bloomHash<span class="token punctuation">,</span> injectorIndex<span class="token punctuation">,</span> tView<span class="token punctuation">.</span>data<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token comment">// 在这一点上，我们有一个*可能*包含令牌的注入器</span>
          <span class="token comment">// 因此我们逐步浏览与注入器的相应节点相关联的提供程序和指令以获取实例</span>
          <span class="token keyword">const</span> instance<span class="token operator">:</span> <span class="token constant">T</span> <span class="token operator">|</span> <span class="token keyword">null</span> <span class="token operator">=</span> <span class="token generic-function"><span class="token function">searchTokensOnInjector</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>
            injectorIndex<span class="token punctuation">,</span>
            lView<span class="token punctuation">,</span>
            token<span class="token punctuation">,</span>
            previousTView<span class="token punctuation">,</span>
            flags<span class="token punctuation">,</span>
            hostTElementNode
          <span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token keyword">if</span> <span class="token punctuation">(</span>instance <span class="token operator">!==</span> <span class="token constant">NOT_FOUND</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> instance<span class="token punctuation">;</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        parentLocation <span class="token operator">=</span> lView<span class="token punctuation">[</span>injectorIndex <span class="token operator">+</span> NodeInjectorOffset<span class="token punctuation">.</span><span class="token constant">PARENT</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>
          parentLocation <span class="token operator">!==</span> <span class="token constant">NO_PARENT_INJECTOR</span> <span class="token operator">&amp;&amp;</span>
          <span class="token function">shouldSearchParent</span><span class="token punctuation">(</span>
            flags<span class="token punctuation">,</span>
            lView<span class="token punctuation">[</span><span class="token constant">TVIEW</span><span class="token punctuation">]</span><span class="token punctuation">.</span>data<span class="token punctuation">[</span>injectorIndex <span class="token operator">+</span> NodeInjectorOffset<span class="token punctuation">.</span><span class="token constant">TNODE</span><span class="token punctuation">]</span> <span class="token operator">===</span>
              hostTElementNode
          <span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
          <span class="token function">bloomHasToken</span><span class="token punctuation">(</span>bloomHash<span class="token punctuation">,</span> injectorIndex<span class="token punctuation">,</span> lView<span class="token punctuation">)</span>
        <span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token comment">// 在此节点上的任何位置都找不到 def，因此它是误报。遍历树并继续搜索</span>
          previousTView <span class="token operator">=</span> tView<span class="token punctuation">;</span>
          injectorIndex <span class="token operator">=</span> <span class="token function">getParentInjectorIndex</span><span class="token punctuation">(</span>parentLocation<span class="token punctuation">)</span><span class="token punctuation">;</span>
          lView <span class="token operator">=</span> <span class="token function">getParentInjectorView</span><span class="token punctuation">(</span>parentLocation<span class="token punctuation">,</span> lView<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
          <span class="token comment">// 如果我们不应该搜索父对象，或者如果祖先的 bloom 过滤器值没有对应于该指令的位</span>
          <span class="token comment">// 我们可以放弃遍历以查找特定的注入器</span>
          injectorIndex <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">return</span> <span class="token generic-function"><span class="token function">lookupTokenUsingModuleInjector</span><span class="token generic class-name"><span class="token operator">&lt;</span><span class="token constant">T</span><span class="token operator">&gt;</span></span></span><span class="token punctuation">(</span>lView<span class="token punctuation">,</span> token<span class="token punctuation">,</span> flags<span class="token punctuation">,</span> notFoundValue<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>从上述代码中，如果我们调用<code>injector.get(SomeClass)</code>方法，会产生以下步骤：</p> <ol><li>Angular 在<code>SomeClass.__NG_ELEMENT_ID__</code>静态属性中查找哈希。</li> <li>如果该哈希是工厂函数，则还有另一种特殊情况，即应通过调用该函数来初始化对象。</li> <li>如果该哈希等于-1，则是一种特殊情况，我们将获得<code>NodeInjector</code>实例。</li> <li>如果该哈希是一个数字，那么我们会从<code>TNode</code>获取<code>injectorIndex</code>。</li> <li>查看模板布隆过滤器（<code>TView.data [injectorIndex]</code>），如果为真，那么我们将搜索<code>SomeClass</code>令牌（通过<code>tNode.providerIndexes</code>可以找到所需的令牌）。</li> <li>如果模板布隆过滤器返回错误，那么会查看一下累积布隆过滤器。如果它为真，则继续进行遍历，否则将切换到<code>ModuleInjector</code>。</li></ol> <p>该过程可以用以下流程图表示：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/angular-ivy-2-2.png" alt=""></p> <p>这便是在 Ivy 中，使用<code>NodeInjector</code>来解析依赖关系的过程。可以看到，该过程中还使用了两个布隆过滤器：累积布隆过滤器（cumulativeBloom）和模板布隆过滤器（templateBloom）。</p> <h3 id="布隆过滤器"><a href="#布隆过滤器" class="header-anchor">#</a> 布隆过滤器</h3> <p>布隆过滤器常用于加快数据检索的过程，属于哈希函数的一种，你可以阅读 <a href="https://hackernoon.com/probabilistic-data-structures-bloom-filter-5374112a7832" target="_blank" rel="noopener noreferrer">Probabilistic Data structures: Bloom filter<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 一文来了解它。</p> <p>在 Ivy 中，一个视图可以具有与为该视图上的节点创建的注入器数量一样多的布隆过滤器。下图为可视化结果：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/angular-ivy-2-1.png" alt=""></p> <p>可以看到，布隆过滤器存储在前面提到的<code>LView/TView.data</code>布局中的<code>EXPANDO</code>部分:</p> <ul><li><code>LView</code>和<code>TView.data</code>数组可以包含许多布隆过滤器，长度为 8 个时隙（[n，n + 7]索引），它们的数量与为其创建喷射器的节点数量成正比</li> <li>每个布隆过滤器在“压缩的”<code>parentLocation</code>插槽（n + 8 索引）中都有一个指向父布隆过滤器的指针</li></ul> <p>我们结合<code>NodeInjector</code>中查找依赖的过程，以以下简单的代码为例：</p> <div class="language-ts extra-class"><pre class="language-ts"><code><span class="token decorator"><span class="token at operator">@</span><span class="token function">Component</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  selector<span class="token operator">:</span> <span class="token string">&quot;my-app&quot;</span><span class="token punctuation">,</span>
  template<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
    &lt;div dirA&gt;
      &lt;div dirB&gt;Hello Ivy&lt;/div&gt;
    &lt;/div&gt;
  </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">AppComponent</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>

<span class="token decorator"><span class="token at operator">@</span><span class="token function">Directive</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> selector<span class="token operator">:</span> <span class="token string">&quot;[dirA]&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">DirA</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>

<span class="token decorator"><span class="token at operator">@</span><span class="token function">Directive</span></span><span class="token punctuation">(</span><span class="token punctuation">{</span> selector<span class="token operator">:</span> <span class="token string">&quot;[dirB]&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">export</span> <span class="token keyword">class</span> <span class="token class-name">DirB</span> <span class="token punctuation">{</span>
  <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token keyword">private</span> rootComp<span class="token operator">:</span> AppComponent<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>在 Ivy 中，上述代码会生成这样的可视化视图：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/angular-ivy-2-3.png" alt=""></p> <p>Ivy 在<code>TNode</code>上创建了<code>InjectorIndex</code>属性，以便知道专用于此节点布隆过滤器的位置。除此之外，Ivy 还在<code>LView</code>数组中存储了<code>parentLocation</code>指针，以便我们可以遍历所有父注入器。</p> <p>而我们也看到，<code>NodeInjector</code>是具有对<code>TNode</code>和<code>LView</code>对象的引用的对象。因此，每个<code>NodeInjector</code>分别保存在<code>LView</code>的 9 个连续插槽和<code>TView.data</code>的 9 个连续插槽中，如图：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/angular-ivy-2-4.png" alt=""></p> <p>那么，上面简单的代码示例中，DI 查找依赖的过程如图：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/angular-ivy-2-5.png" alt=""></p> <blockquote><p>以上例子来自于 <a href="https://indepth.dev/posts/1268/angular-di-getting-to-know-the-ivy-nodeinjector" target="_blank" rel="noopener noreferrer">Angular DI: Getting to know the Ivy NodeInjector<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></blockquote> <h2 id="总结"><a href="#总结" class="header-anchor">#</a> 总结</h2> <p>今天给大家介绍了 Ivy 编译器中的数据视图<code>LView/TView</code>，而依赖解析过程中需要从中取出对应的数据，该过程使用到<code>NodeInjector</code>。<code>NodeInjector</code>用于创建注入器，为了加快 DI 搜索依赖的过程，Ivy 还设计了累加布隆过滤器和模板布隆过滤器。</p> <p>这些内容，是理解 Angular 中依赖注入过程中不可或缺的。而在查阅这部分文章和代码之前，我甚至无法想象在 Angular 中依赖注入过程如此复杂。很多时候，我们都认为前端领域并不存在太多的算法和数据结构相关的内容，实际上可能只是我们并没有接触到而已。</p> <h3 id="参考"><a href="#参考" class="header-anchor">#</a> 参考</h3> <ul><li><a href="https://indepth.dev/posts/1268/angular-di-getting-to-know-the-ivy-nodeinjector" target="_blank" rel="noopener noreferrer">Angular DI: Getting to know the Ivy NodeInjector<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://github.com/angular/angular/blob/master/packages/core/src/render3/VIEW_DATA.md" target="_blank" rel="noopener noreferrer">DOCS: View Data Explanation<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://hackernoon.com/probabilistic-data-structures-bloom-filter-5374112a7832" target="_blank" rel="noopener noreferrer">Probabilistic Data structures: Bloom filter<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div> <!----> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/godbasin/front-end-playground/edit/sourcecode/docs/front-end-others/deep-into-angular/angular-design-ivy-1-view-data-and-node-injector.md" target="_blank" rel="noopener noreferrer">帮阿猪改善此页面！</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <!----> <blockquote>部分文章中使用了一些网站的截图，如果涉及侵权，请告诉我删一下谢谢~</blockquote> <div style="margin-top:30px;"><div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-sm-0 el-col-md-2 el-col-lg-4" style="padding-left:10px;padding-right:10px;display:block;"><div style="width:1px;height:1px;"></div></div> <div class="el-col el-col-24 el-col-sm-24 el-col-md-18 el-col-lg-16" style="padding-left:10px;padding-right:10px;"><div class="el-card box-card is-always-shadow"><div class="el-card__header"><div class="clearfix"><span>温馨提示喵</span></div></div><div class="el-card__body"> <div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="el-image"><div class="image-slot"><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/loading.gif" style="width:100%;"></div><!----></div></div> <div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="copyright-text"><div>本文版权归作者所有，欢迎转载，但未经作者同意必须保留此段声明，且在文章页面明显位置给出原文连接，否则保留追究法律责任的权利。</div> <div>出处：被删的前端游乐场</div> <div>作者：<a href="https://github.com/godbasin" target="_blank">被删</a></div></div></div></div></div></div></div></div></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/front-end-playground/front-end-others/deep-into-angular/angular-design-ivy-0-design.html" class="prev">
          9.Ivy编译器整体设计
        </a></span> <span class="next"><a href="/front-end-playground/front-end-others/angular-free/0-about-angular-from-1-to-4.html">
          谈谈 AngularJS 到 Angular
        </a>
        →
      </span></p></div>  <div class="gitalk-container theme-default-content"><div id="gitalk-container" class="content"></div></div></main> <div id="kitty-container"><span><div role="tooltip" id="el-popover-4071" aria-hidden="true" class="el-popover el-popper" style="width:undefinedpx;display:none;"><!----><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/2code2.jpg" class="image"> <div class="text">牡羊猪的猫粮罐</div> </div><span class="el-popover__reference-wrapper"><div id="kitty" style="background:url(https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/kitty0.svg);"></div></span></span> <div class="el-dialog__wrapper" style="display:none;"><div role="dialog" aria-modal="true" aria-label="牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）" class="el-dialog" style="margin-top:15vh;"><div class="el-dialog__header"><span class="el-dialog__title">牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）</span><button type="button" aria-label="Close" class="el-dialog__headerbtn"><i class="el-dialog__close el-icon el-icon-close"></i></button></div><!----><!----></div></div></div></div><div class="global-ui"></div></div>
    <script src="/front-end-playground/assets/js/app.1e2670bf.js" defer></script><script src="/front-end-playground/assets/js/2.38d016d1.js" defer></script><script src="/front-end-playground/assets/js/3.e3f029cb.js" defer></script><script src="/front-end-playground/assets/js/109.a96adbae.js" defer></script>
  </body>
</html>
